package utils

import (
	"context"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
)

const (
	CodeLength      = 6
	RedisKeyPrefix  = "verification_code:"
	RedisExpiration = 10 * time.Minute
)

func GenerateVerificationCode() string {
	code := ""
	for i := 0; i < CodeLength; i++ {
		code += strconv.Itoa(rand.Intn(10))
	}
	return code
}

func SaveCache(key string, data string) error {
	ctx := context.Background()
	return Redis.Set(ctx, key, data, 0).Err()
}

func GetUserIP(id int64) (string, error) {
	ctx := context.Background()
	val, err := Redis.Get(ctx, strconv.Itoa(int(id))).Result()
	return val, err
}

func SaveOnLineUser(id uint) {
	ctx := context.Background()
	err := Redis.SAdd(ctx, "online", id).Err()

	if err != nil {
		fmt.Printf("Failed to save user online in Redis: %v\n", err)
		// 处理错误...
	}
}

func IsUserOnline(id uint) (bool, error) {
	ctx := context.Background()
	exists, err := Redis.SIsMember(ctx, "online", id).Result()

	if err != nil {
		fmt.Printf("Failed to check if user is online in Redis: %v\n", err)
		// Handle error...
		return false, err
	}
	return exists, nil
}

func RemoveOfflineUser(id uint) {
	ctx := context.Background()
	err := Redis.SRem(ctx, "online", id).Err()

	if err != nil {
		fmt.Printf("Failed to remove user from online in Redis: %v\n", err)
		// 处理错误...
	}
}

func SaveVerificationCode(key string, code string) {
	ctx := context.Background()
	redisKey := RedisKeyPrefix + key
	err := Redis.Set(ctx, redisKey, code, RedisExpiration).Err()
	if err != nil {
		fmt.Printf("Failed to save verification code in Redis: %v\n", err)
		// Handle error...
	}
}

func GetVerificationCodeFromRedis(key string) (string, error) {
	ctx := context.Background()
	redisKey := RedisKeyPrefix + key
	code, err := Redis.Get(ctx, redisKey).Result()
	if err == redis.Nil {
		// 验证码不存在，可以根据业务需求处理该情况
		return "验证码错误", fmt.Errorf("Verification code not found")
	} else if err != nil {
		// 发生其他错误，可以根据业务需求处理该情况
		return "", err
	}

	return code, nil
}

// 定义一个结构体来存储JWT的claims
type Claims struct {
	UserID string `json:"userid"`
	jwt.StandardClaims
}

var JwtSecret = []byte("electron-yyy-jwt-secret")

// 中间件函数进行身份验证
func AuthMiddleware(c *gin.Context) {
	// 从请求头获取JWT
	tokenString := c.GetHeader("Authorization")
	if excludeAuthRoutes(c.Request.URL.Path) {
		c.Next()
		return
	}
	if tokenString == "" {
		RespTokenFail(c.Writer, "Authorization header is missing")
		c.Abort() // 终止请求处理链
		return
	}
	// 解析JWT
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return JwtSecret, nil
	})
	if err != nil {
		if err == jwt.ErrSignatureInvalid {
			RespTokenFail(c.Writer, "Invalid token signature")
			c.Abort()
			return
		}
		RespTokenFail(c.Writer, "Failed to parse JWT")
		c.Abort()
		return
	}
	// 校验JWT的有效性
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		// 将解析后的用户信息存储到上下文中，以便后续的处理函数使用
		c.Set("userID", claims.UserID)
		c.Next() // 继续处理下一个中间件或路由处理函数
	} else {
		RespTokenFail(c.Writer, "Invalid token")
		c.Abort()
	}
}

// 判断是否需要排除验证的路由
func excludeAuthRoutes(path string) bool {
	excludedRoutes := []string{
		"/user/get-verification-code",
		"/user/login",
		"/user/register",
		"/user/chat",
		// 添加其他不需要验证的路由
	}

	for _, route := range excludedRoutes {
		if route == path || strings.HasPrefix(path, "/static/") {
			return true
		}
	}
	return false
}
